==================================
CHR$128 UDG Mode for the ZX80/ZX81
==================================

ZX81 SUPPORT

Adding RAM on the ZX81 between $2000-$3FFF allows redefinition of the basic 64
character set patterns (character codes 0 to 63). Character codes (128 to 191)
are inverse versions of these definitions and are generated by the hardware of
the display mechanism. The mode is invoked by setting the I register to an even
number between $20 to $3E, meaning there are 16 possible table locations:

I Register  Table location
$20         $2000-$21FF
$22         $2200-$23FF
$24         $2400-$25FF
$26         $2600-$27FF
$28         $2800-$29FF
$2A         $2A00-$2BFF
$2C         $2C00-$2DFF
$2E         $2E00-$2FFF
$30         $3000-$31FF
$32         $3200-$33FF
$34         $3400-$35FF
$36         $3600-$37FF
$38         $3800-$39FF
$3A         $3A00-$3BFF
$3C         $3C00-$3DFF
$3E         $3E00-$3FFF

CHR$128 mode extends on this principle by using bit 0 of the I register to
select between two tables of definitions. This allows redefinition of all 128
displayable characters. The pixel pattern table therefore occupies in 1K of RAM
between the $2000-$3FFF region on the ZX81. When bit 0 of the I register is 0
then CHR$128 mode only allows the basic 64 characters to be redefined, and when
bit 0 is 1 then all 128 characters can be redefined.

When bit 0 is set to 1, the first 0.5K holds the pixel patterns for the non-
inverted characters, and the second 0.5K holds the pixel patterns for the
inverted characters. Note that the pixel patterns for the 'inverted' characters
need to be stored in inverted form since the ZX81 display mechanism automatically
inverts them due to bit 7 being set of the character code.

With bit 0 set to 1, there are only 8 possible character set table locations:

I Register  Table location
$20         $2000-$23FF
$24         $2400-$27FF
$28         $2800-$2BFF
$2C         $2C00-$2FFF
$30         $3000-$33FF
$34         $3400-$37FF
$38         $3800-$3BFF
$3C         $3C00-$3FFF


ZX80 SUPPORT

The Chroma 80 interface adds CHR$128 mode support to the ZX80, but it does so
in the $C000-$FFFF region since the mirroring of the ROM in the $2000-$3FFF
region cannot be suppressed via the expansion bus.


ARX DISPLAY DRIVER

The ARX display driver was devised by Andy Rea for the ZX81 and utilises the
basic 64 character UDG mode to generate a full high resolution display.

It displays 12 full characters sets on the screen at the same time such that
each position of the display is populated with a unique character. Hence the
first two rows contains the characters from character set 1, the next two rows
the characters from character set 2, the next two rows the characters from
character set 3, etc. In this way, the whole display is filled using 12 character
sets, i.e. 12 x 64 = 768 = 24 x 32.

A program may now redefine the characters of the 12 characters on the fly to
achieve a fully dynamic high resolution display.


	ORG $4082

; This is hi-res routine based on WRX16, except it uses RAM at 8K-16K above ROM.
; However this RAM is addressed like ROM, during refresh, ie. Bits 0-2 are the
; line ula row counter, bits 3-8 are the char from d-file/my dummy d-file.
; What's more is this RAM can be used as Chr$ generator requiring only the
; I register to change. But can equally be used for code execution.

LBUF1:	DEFB $00, $01, $02, $03, $04, $05, $06, $07
	DEFB $08, $09, $0A, $0B, $0C, $0D, $0E, $0F
	DEFB $10, $11, $12, $13, $14, $15, $16, $17
	DEFB $18, $19, $1A, $1B, $1C, $1D, $1E, $1F
	RET

LBUF2:	DEFB $20, $21, $22, $23, $24, $25, $26, $27
	DEFB $28, $29, $2A, $2B, $2C, $2D, $2E, $2F
	DEFB $30, $31, $32, $33, $34, $35, $36, $37
	DEFB $38, $39, $3A, $3B, $3C, $3D, $3E, $3F
	RET

; Because of the way this RAM is addressed during refresh, 2 dummy D-file lines
; are needed, the first to do even character rows, the second to do odd character
; rows. So basically the H-file is laid out like 12 consecutive character maps.
;
; Each buffer is called 8 times as video bytes both repeated 12 times in total,
; i.e. (8+8)*12=192 scanlines.
;
; This is the main loop. When its time to display the video, it needs to be
; synchromised with the ULA row counter. The effect is to slow down basic
; execution by effectively 8 scanlines worth.

ARX:    LD   B,$78			; Between here
					; and the first
DELAY:	DJNZ DELAY			; execution of
					; the LBUF bytes,
	INC  BC				; the total delay is
	NOP				; equal to 8 scanlines.

	LD   D,$08			; Set up initial registers.
	LD   B,$0C
	LD   C,D
	LD   A,$20
	LD   I,A

ARX1:	CALL LBUF1 + $8000		; 17	17 T-states so far.
	NOP				; 4	159 T-states so far (138 from LBUF1).
	DEC  C				; 4	163 T-states.
	JP   Z,ARX2			; 10	173 T-states, conditional JP uses 10 T-states either way.

; This way if not 8 scanlines.

	LD   A,I			; 9	182 T-states.
	LD   A,I			; 9	191 T-states.
	NOP				; 4	195 T-states.
	JR   ARX1			; 12	207 T-states !!!

; This is the end of the first loop. This route is taken once 8 scanlines have been completed.

ARX2:	LD   A,I			; 9	182 T-states
	INC  BC				; 6	188 T-states, doesn't matter about C as gets reloaded.
	INC  BC				; 6	194 T-states.
	LD   C,D			; 4	198 T-states.
	LD   A,I			; 9	207 T-states !!!

; The start of the second inner loop.

ARX3:	CALL LBUF2 + $8000		; 17	17 T-states.
	DEC  C				; 4	159 T-states (138 from LBUF2).
	JP   Z,ARX4			; 10	169 T-states.

; This branch taken if not 8 scan lines.

	LD   A,I			; 9	178 T-states.
	LD   A,I			; 9	187 T-states.
	INC  A				; 4     191 T-states.
	INC  A				; 4     195 T-states, with A incremented by 2 ready for the other branch.
	JR   ARX3			; 12	207 T-states !!!

ARX4:	LD   C,D			; 4	173 T-states, reset scan line counter.
	LD   I,A			; 9	182 T-states, set I to next 512 byte block.
	LD   A,(HL)			; 7	189 T-states.
	NOP				; 4	193 T-states.
	DEC  B				; 4 	197 T-states.
	JP   NZ,ARX1			; 10	207 T-states !!!

; The following section is virtually the same as Wilf Rigter's WRX16 display driver.

	LD   IX,ARX5
	JR   ARX6

; Generate the VSync pulse.

ARX5:	CALL $0220			; Use the ROM to generate the VSync pulse.
	LD  IX,ARX

ARX6:	LD A,($4028)			; 33 or 19 blank lines in bottom MARGIN.
	SUB  $08			; Reduce by 8 scanlines.
	JP   $029E     			; Start NMI, POP registers and RETURN.

; Stops the hi-res display and returns to normal display mode, this is the same as WRX16.

STOP:	LD   HL,$0281 			; Pointer to ROM video routine.
	LD   A,$1E    			; ROM pattern table base address ($1E00).
	LD   I,A
	JR   SYNC

; Starts the hi-res display.

START:	LD   HL,ARX   			; Pointer to the hi-res display driver.

SYNC:  	PUSH HL				; Used by START and STOP to smoothly change the display mode.

; This check gets stuck if running in fast mode.

	LD   HL,$4034			; The FRAMES counter.
	LD   A,(HL)			; Get old FRAMES.
SLOOP:	CP   (HL)			; Compare to new FRAMES.
	JR   Z,SLOOP			; Exit after a change is detected.

	POP  IX
	RET